﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

using System.Reflection;

namespace CXJ.DLL
{
    public class DataOperater : Interface.IDataOperater
    {
        private Interface.IBaseEntity _BaseEntity;

        public DataOperater() { }

        public DataOperater(Interface.IBaseEntity parm)
        {
            _BaseEntity = parm;
        }

        #region IDataOperater 成员
        public Object ErrMsg
        {
            get;
            set;
        }
        public CXJ.Interface.IBaseEntity BaseEntity
        {
            get { return _BaseEntity; }
            set { _BaseEntity = value; }
        }

        public DataSet Select()
        {
            try
            {
                if (string.IsNullOrEmpty(BaseEntity.SelectStatement)) return null;
                return Libiary.DBManager.Instance.GetDataSet(BaseEntity.SelectStatement);
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                return null;
            }
        }

        public DataSet Select(CXJ.Interface.IBaseEntity entity)
        {
            try
            {
                if (string.IsNullOrEmpty(entity.SelectStatement)) return null;
                IDataParameter[] parms = CreateParameter(entity, CXJ.Interface.OperateMode.Select);
                return Libiary.DBManager.Instance.GetDataSet(entity.SelectStatement + entity.ConditionStatement, parms);
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                return null;
            }
        }
        public List<CXJ.Interface.IBaseEntity> GetEntityList()
        {
            List<CXJ.Interface.IBaseEntity> entityList = new List<CXJ.Interface.IBaseEntity>();
            try
            {
                if (string.IsNullOrEmpty(BaseEntity.SelectStatement)) return null;
                using (IDataReader dataReader = Libiary.DBManager.Instance.GetReader(BaseEntity.SelectStatement))
                {
                    entityList = SetValueInReader(dataReader);
                }
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                return null;
            }
            return entityList;
        }
        public List<CXJ.Interface.IBaseEntity> GetEntityList(CXJ.Interface.IBaseEntity entity)
        {
            List<CXJ.Interface.IBaseEntity> entityList = new List<CXJ.Interface.IBaseEntity>();
            try
            {
                if (string.IsNullOrEmpty(entity.SelectStatement)) return null;
                IDataParameter[] parms = CreateParameter(entity, CXJ.Interface.OperateMode.Select);
                using (IDataReader dataReader = Libiary.DBManager.Instance.GetReader(entity.SelectStatement + entity.ConditionStatement, parms))
                {
                    entityList = SetValueInReaderList(dataReader, entity);
                }
                PostEntityMx(entityList);
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                return null;
            }
            return entityList;
        }

        private void PostEntityMx(List<CXJ.Interface.IBaseEntity> list)
        {
            foreach (CXJ.Interface.IBaseEntity entity in list)
            {
                Type t = entity.GetType();
                foreach (System.Reflection.PropertyInfo property in t.GetProperties())
                {
                    if (property.PropertyType.Name.Length > 12 && property.PropertyType.Name.Substring(0, 13) == "IBaseEntity[]")
                    {
                        CXJ.Interface.IBaseEntity[] listmx = (CXJ.Interface.IBaseEntity[])property.GetValue(entity, null);
                        property.SetValue(entity, GetEntityMx(listmx, entity), null);
                    }
                }
            }
        }
        private object GetEntityMx(CXJ.Interface.IBaseEntity[] listmx, CXJ.Interface.IBaseEntity entityfather)
        {
            if (listmx == null) return null;
            CXJ.Interface.IBaseEntity[] returnList = new CXJ.Interface.IBaseEntity[0];
            string fullName = listmx.GetType().FullName;
            fullName = fullName.Substring(0, fullName.Length - 2);
            Type objs = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "CXJ.Model.dll").GetType(fullName);
            CXJ.Interface.IBaseEntity entity = objs.GetConstructor(Type.EmptyTypes).Invoke(null) as CXJ.Interface.IBaseEntity;

            if (objs.GetProperty(entityfather.PK) == null) { return null; }
            objs.GetProperty(entityfather.PK).SetValue(entity, entityfather.PK_VALUE, null);
            returnList = this.GetEntityList(entity).ToArray();
            return returnList;
        }

        public bool Operate(CXJ.Interface.IBaseEntity entity, CXJ.Interface.OperateMode operateMode)
        {
            IDataParameter[] parms = CreateParameter(entity, operateMode);
            bool ret = false;
            try
            {
                switch (operateMode)
                {
                    case CXJ.Interface.OperateMode.Insert:
                        ret = (Libiary.DBManager.Instance.ExecuteSql(entity.InsertStatement, parms) > 0);
                        break;
                    case CXJ.Interface.OperateMode.Update:
                        ret = (Libiary.DBManager.Instance.ExecuteSql(entity.UpdateStatement, parms) > 0);
                        break;
                    case CXJ.Interface.OperateMode.Delete:
                        ret = (Libiary.DBManager.Instance.ExecuteSql(entity.DeleteStatement, parms) > 0);
                        break;
                }
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                ret = false;
            }
            return ret;
        }

        public bool TranceOperate(Dictionary<CXJ.Interface.OperateMode, CXJ.Interface.IBaseEntity[]> lists)
        {
            bool ret = false;
            Libiary.DBManager.Instance.BeginTransaction();
            try
            {
                if (lists[CXJ.Interface.OperateMode.Insert] != null)
                {
                    foreach (Interface.IBaseEntity item in lists[CXJ.Interface.OperateMode.Insert])
                    {
                        if (!Operate(item, CXJ.Interface.OperateMode.Insert))
                        {
                            Libiary.DBManager.Instance.RollbackTransaction();
                            return false;
                        }
                    }
                }

                if (lists[CXJ.Interface.OperateMode.Update] != null)
                {
                    foreach (Interface.IBaseEntity item in lists[CXJ.Interface.OperateMode.Update])
                    {
                        if (!Operate(item, CXJ.Interface.OperateMode.Update))
                        {
                            Libiary.DBManager.Instance.RollbackTransaction();
                            return false;
                        }
                    }
                }

                if (lists[CXJ.Interface.OperateMode.Delete] != null)
                {
                    foreach (Interface.IBaseEntity item in lists[CXJ.Interface.OperateMode.Delete])
                    {
                        if (!Operate(item, CXJ.Interface.OperateMode.Delete))
                        {
                            Libiary.DBManager.Instance.RollbackTransaction();
                            return false;
                        }
                    }
                }
                Libiary.DBManager.Instance.CommitTransaction();
                ret = true;
            }
            catch (Exception ex)
            {
                ErrMsg = ex.Message;
                Libiary.DBManager.Instance.RollbackTransaction();
                ret = false;
                throw;
            }

            return ret;
        }

        public IDataParameter[] CreateParameter(CXJ.Interface.IBaseEntity entity, CXJ.Interface.OperateMode operateMode)
        {
            IDataParameter[] parameter = new IDataParameter[] { };
            try
            {
                switch (operateMode)
                {
                    case CXJ.Interface.OperateMode.Select:
                        parameter = CreateParameter_Select(entity);
                        break;
                    case CXJ.Interface.OperateMode.Insert:
                        parameter = CreateParameter_Insert(entity);
                        break;
                    case CXJ.Interface.OperateMode.Update:
                        parameter = CreateParameter_Update(entity);
                        break;
                    case CXJ.Interface.OperateMode.Delete:
                        parameter = CreateParameter_Delete(entity);
                        break;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return parameter.ToArray();
        }



        #endregion

        public virtual IDataParameter[] CreateParameter_Select(CXJ.Interface.IBaseEntity entity)
        {
            List<IDataParameter> parameter = new List<IDataParameter>();
            string tempCondition = " WHERE (1=1) ";
            if (entity != null)
            {
                try
                {
                    Type entityType = entity.GetType();
                    foreach (System.Reflection.PropertyInfo item in entityType.GetProperties())
                    {
                        Libiary.DBColumnAttribue tempAttribue = GetColumnAttribue(item);
                        if (tempAttribue == null || !tempAttribue.IsDBColumn) { continue; }

                        if (item.GetValue(entity, null) != null && item.GetValue(entity, null).ToString() != "")
                        {
                            if (item.Name == entity.PK)
                            {
                                tempCondition += " AND " + item.Name + " = @" + item.Name + " ";
                                parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, item.GetValue(entity, null).ToString(), DbType.String));
                            }
                            else
                            {
                                switch (tempAttribue.DBType)
                                {
                                    case DbType.Int32:
                                    case DbType.Double:
                                    case DbType.Boolean:
                                        tempCondition += " AND " + item.Name + " = @" + item.Name + " ";
                                        parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, item.GetValue(entity, null).ToString(), DbType.String));
                                        break;
                                    case DbType.DateTime:
                                    case DbType.DateTime2:
                                        continue;
                                    default:
                                        tempCondition += " AND " + item.Name + " LIKE @" + item.Name + " ";
                                        parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, "%" + item.GetValue(entity, null).ToString() + "%", DbType.String));
                                        break;
                                }

                            }

                        }
                    }
                    entity.ConditionStatement = tempCondition;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return parameter.ToArray();
        }

        public virtual IDataParameter[] CreateParameter_Insert(CXJ.Interface.IBaseEntity entity)
        {
            List<IDataParameter> parameter = new List<IDataParameter>();
            if (entity != null)
            {
                try
                {
                    Type entityType = entity.GetType();
                    foreach (System.Reflection.PropertyInfo item in entityType.GetProperties())
                    {
                        if (!CheckIsColumn(item)) { continue; }
                        if (item.GetValue(entity, null) != null && item.GetValue(entity, null).ToString() != "")
                        {
                            parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, item.GetValue(entity, null).ToString(), DbType.String));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return parameter.ToArray();
        }

        public virtual IDataParameter[] CreateParameter_Update(CXJ.Interface.IBaseEntity entity)
        {
            List<IDataParameter> parameter = new List<IDataParameter>();
            if (entity != null)
            {
                try
                {
                    Type entityType = entity.GetType();
                    foreach (System.Reflection.PropertyInfo item in entityType.GetProperties())
                    {
                        if (!CheckIsColumn(item)) { continue; }
                        if (item.GetValue(entity, null) != null && item.GetValue(entity, null).ToString() != "")
                        {
                            parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, item.GetValue(entity, null).ToString(), DbType.String));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return parameter.ToArray();
        }

        public virtual IDataParameter[] CreateParameter_Delete(CXJ.Interface.IBaseEntity entity)
        {
            List<IDataParameter> parameter = new List<IDataParameter>();
            if (entity != null)
            {
                try
                {
                    Type entityType = entity.GetType();
                    foreach (System.Reflection.PropertyInfo item in entityType.GetProperties())
                    {
                        if (!CheckIsColumn(item)) { continue; }

                        if (item.GetValue(entity, null) != null && item.GetValue(entity, null).ToString() != "")
                        {
                            parameter.Add(Libiary.DBManager.Instance.CreateParameter(item.Name, item.GetValue(entity, null).ToString(), DbType.String));
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            return parameter.ToArray();
        }

        public bool CheckIsColumn(System.Reflection.PropertyInfo item)
        {
            try
            {
                object[] objs = item.GetCustomAttributes(typeof(CXJ.Libiary.DBColumnAttribue), true);
                if (objs.Length == 0) return false;
                CXJ.Libiary.DBColumnAttribue pAttribute = objs[0] as CXJ.Libiary.DBColumnAttribue;
                return pAttribute.IsDBColumn;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public CXJ.Libiary.DBColumnAttribue GetColumnAttribue(System.Reflection.PropertyInfo item)
        {
            try
            {
                object[] objs = item.GetCustomAttributes(typeof(CXJ.Libiary.DBColumnAttribue), true);
                if (objs.Length == 0) return null;
                CXJ.Libiary.DBColumnAttribue pAttribute = objs[0] as CXJ.Libiary.DBColumnAttribue;
                return pAttribute;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void SetValueInReader(IDataReader dataReader, Interface.IBaseEntity baseEntity)
        {
            Type m_Type = baseEntity.GetType();
            foreach (System.Reflection.PropertyInfo item in m_Type.GetProperties())
            {
                if (!CheckIsColumn(item)) continue;
                item.SetValue(baseEntity, dataReader[item.Name].ToString(), null);
            }
        }
        private List<CXJ.Interface.IBaseEntity> SetValueInReader(IDataReader dataReader)
        {
            List<CXJ.Interface.IBaseEntity> list = new List<CXJ.Interface.IBaseEntity>();
            Type m_Type = BaseEntity.GetType();
            while (dataReader.Read())
            {
                CXJ.Interface.IBaseEntity entity = BaseEntity.Clone() as CXJ.Interface.IBaseEntity;
                foreach (System.Reflection.PropertyInfo item in m_Type.GetProperties())
                {
                    if (!CheckIsColumn(item)) continue;
                    item.SetValue(entity, dataReader[item.Name].ToString(), null);
                }
                list.Add(entity);
            }
            return list;
        }
        private List<CXJ.Interface.IBaseEntity> SetValueInReaderList(IDataReader dataReader, CXJ.Interface.IBaseEntity entityPara)
        {
            List<CXJ.Interface.IBaseEntity> list = new List<CXJ.Interface.IBaseEntity>();
            Type m_Type = entityPara.GetType();
            while (dataReader.Read())
            {
                CXJ.Interface.IBaseEntity entity = entityPara.Clone() as CXJ.Interface.IBaseEntity;
                foreach (System.Reflection.PropertyInfo item in m_Type.GetProperties())
                {
                    if (!CheckIsColumn(item)) continue;
                    item.SetValue(entity, dataReader[item.Name].ToString(), null);
                }
                list.Add(entity);
            }
            return list;
        }
    }
}
